﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Communication.Base;
using UtilZ.Dotnet.Ex.Communication.Net.Base;
using UtilZ.Dotnet.Ex.Communication.Net.Tcp;
using UtilZ.Dotnet.Ex.DataStatistic;
using UtilZ.Dotnet.Ex.Log;

namespace ConAppCore
{
    internal class TestNetTcpListener : UnpackerAbs
    {

        public static void Test()
        {
            //int timeout = 5000;
            //Semaphore semaphore = new Semaphore(2, 2);

            //bool ret1 = semaphore.WaitOne(timeout);
            //bool ret2 = semaphore.WaitOne(timeout);
            //bool ret3 = semaphore.WaitOne(timeout);

            //semaphore.Release();
            //bool ret4 = semaphore.WaitOne(timeout);

            using var obj = new TestNetTcpListener();

            Console.WriteLine("any key exit TestNetTcpListener");
            Console.ReadKey();
            Console.WriteLine("TestNetTcpListener end");
        }



        private readonly NetTcpListener _serverListener;
        private readonly List<NetTcpClient> _clientList = new List<NetTcpClient>();
        private readonly NetTcpClient _sendClient;
        private readonly ThreadEx _sendDataThread;
        private TestNetTcpListener()
        {
            var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
            var initPara = new NetTcpListenerInitPara(endPoint, 0)
            {
                //AcceptMode = ThreadMode.Async,
                AcceptMode = ThreadMode.Sync,
                MaxConnections = 1
            };
            this._serverListener = new NetTcpListener(this.AcceptSocketCallback, initPara);
            this._serverListener.Start();
            Loger.Info($"最大连接数为:{initPara.MaxConnections}");

            this._sendDataThread = new ThreadEx(this.SendDataThreadMethod, "sendData", true);
            this._sendClient = new NetTcpClient(new NetTcpClientInitPara(this, endPoint));
            this._sendClient.ConnectChanged += _sendClient_ConnectChanged;
            this._sendClient.ConnectAsync();

            DataStatisticManager.Default.Add(new DataStatisticCallbackItem(1000, StatisticOutputCallback));
        }

        private long _receiveCount = 0L;
        private void StatisticOutputCallback(DataStatisticOutputArgs args)
        {
            var receiveCount = Interlocked.Exchange(ref _receiveCount, 0L);
            if (receiveCount > 0)
            {
                Console.WriteLine($"{args.Duration}ms内收到tcp数据:{receiveCount}包.");
            }
        }


        private void _sendClient_ConnectChanged(object sender, NetConnectedChangedArgs e)
        {
            //if (e.Status == ConnectionStatus.Opened)
            //{
            //    this._sendDataThread.Start(sender);
            //}
            //else
            //{
            //    this._sendDataThread.Stop();
            //}
        }

        private void SendDataThreadMethod(ThreadPara threadPara)
        {
            var client = (NetTcpClient)threadPara.Para;
            long total = 0L;
            try
            {
                byte[] buffer = new byte[8192];
                while (!threadPara.Token.IsCancellationRequested)
                {
                    client.Send(buffer);
                    total += buffer.Length;
                }
            }
            catch (Exception ex)
            {
                Loger.Error(ex, $"已发送数据:{total}byte");
            }
        }

        private TestTcpclient _testTcpclient = null;
        private void AcceptSocketCallback(AcceptSocketArgs args)
        {
            try
            {
                //this._testTcpclient = new TestTcpclient(args.Client);

                var initPara = new NetTcpClientInitPara(this, args);
                initPara.ReceiveDataMode = ThreadMode.Async;
                //initPara.ReceiveDataMode = ThreadMode.Sync;
                initPara.AsyncReceiveStackDepth = 2000;

                var client = new NetTcpClient(initPara);
                Loger.Info($"客户端连接:{NetHelper.GetIPPortString(client.LinkInfo.RemoteEndPoint)}建立");
                client.ConnectChanged += Client_ConnectChanged;

                lock (this._clientList)
                {

                    this._clientList.Add(client);
                }
            }
            catch (ObjectDisposedException)
            { }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        private void Client_ConnectChanged(object sender, NetConnectedChangedArgs e)
        {
            if (e.Status == ConnectionStatus.Closed)
            {
                lock (this._clientList)
                {
                    var client = (NetTcpClient)sender;
                    Loger.Warn($"客户端连接:{NetHelper.GetIPPortString(client.LinkInfo.RemoteEndPoint)}断开");

                    client.ConnectChanged -= Client_ConnectChanged;
                    this._clientList.Remove(client);
                    client.Dispose();
                }
            }
        }

        private void AsyncStartReceive(UdpClient client)
        {
            client.Client.ReceiveBufferSize = 1000000;
            client.Client.SendBufferSize = 10000;

            var v = client.ReceiveAsync();
            v.ContinueWith(e =>
            {
                Encoding.ASCII.GetString(e.Result.Buffer);
                AsyncStartReceive(client);

            });
        }


        private readonly byte[] _buffer = new byte[4096];
        private int _offset = 0;
        private void AsyncStartReceive(TcpClient client)
        {
            client.Client.ReceiveBufferSize = 1000000;
            client.Client.SendBufferSize = 10000;

            NetworkStream stream = client.GetStream();

            //发送
            stream.WriteAsync(_buffer, 0, _buffer.Length);

            //接收
            var result = stream.ReadAsync(_buffer, 0, _buffer.Length, CancellationToken.None);
            result.ContinueWith(e =>
            {
                int revLen = e.Result;
                Encoding.ASCII.GetString(_buffer, 0, revLen);
                stream.ReadAsync(_buffer, 0, _buffer.Length, CancellationToken.None);
            });
        }


        protected override int PrimitiveUnPackge(IUnpackerPara unpackerPara)
        {
            Interlocked.Increment(ref _receiveCount);
            //return 0;
            return unpackerPara.DataLength;
        }


        /// <summary>
        /// Dispose
        /// </summary>
        /// <param name="disposing">标识[true:释放;false:重复释放]</param>
        protected override void Dispose(bool disposing)
        {
            this._serverListener.Stop();
            this._serverListener.Dispose();


            lock (this._clientList)
            {
                foreach (var client in this._clientList)
                {
                    client.ConnectChanged -= Client_ConnectChanged;
                    client.Dispose();
                }
            }
        }

    }

    internal class TestTcpclient : IDisposable
    {
        private readonly Socket _socket;
        private readonly byte[] _buffer = new byte[65536];
        private IAsyncResult _asyncResult;
        private SocketError _socketError = SocketError.Success;

        private int _callbackCount = 0;
        public TestTcpclient(Socket socket)
        {
            this._socket = socket;
            this._asyncResult = this._socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, out this._socketError, this.Callback, null);

            DataStatisticManager.Default.Add(new DataStatisticCallbackItem(1000, StatisticOutputCallback));
        }
        private long _receiveCount = 0L;
        private  void StatisticOutputCallback(DataStatisticOutputArgs args)
        {
            var receiveCount = Interlocked.Exchange(ref _receiveCount, 0L);
            Console.WriteLine($"{args.Duration}ms内收到tcp数据:{receiveCount}包.");
        }



        private void Callback(IAsyncResult ar)
        {
            if (ar.IsCompleted)
            {
                int rcvLen = this._socket.EndReceive(this._asyncResult);
                //Encoding.ASCII.GetString(this._buffer, 0, rcvLen);

                Interlocked.Increment(ref _receiveCount);
                this._callbackCount++;
                if (this._callbackCount > 100)
                {
                    this._callbackCount = 0;

                    Task.Factory.StartNew(() =>
                    {
                        this._asyncResult = this._socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, out this._socketError, this.Callback, null);
                    });
                }
                else
                {
                    this._asyncResult = this._socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, out this._socketError, this.Callback, null);
                }
            }
            else
            {
                if (this._socketError == SocketError.ConnectionReset)
                {
                    //...错误处理
                }
            }
        }


        public void Dispose()
        {
            this._socket.EndReceive(this._asyncResult);
        }
    }
}
